home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-06-15 | 55.5 KB | 1,223 lines |
- /*
- * Copyright (c) 1990, 1991 Stanford University
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that (i) the above copyright notices and this permission notice appear in
- * all copies of the software and related documentation, and (ii) the name
- * Stanford may not be used in any advertising or publicity relating to
- * the software without the specific, prior written permission of
- * Stanford.
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
- * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
- * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
- /* $Header: /Source/Media/collab/TimeLine/RCS/play.c,v 1.16 92/10/30 16:22:49 drapeau Exp $ */
- /* $Log: play.c,v $
- * Revision 1.16 92/10/30 16:22:49 drapeau
- * Fixed minor error in ResumeOrPerformSelections(); before, not all edits would
- * necessarily be played, perhaps due to the way in which the instrument
- * pointer was being advanced.
- *
- * Revision 1.15 92/10/07 15:15:51 drapeau
- * New version of TimeLine adds two command-line options: "-autoPlay" and
- * "-autoQuit". "-autoPlay" indicates that TimeLine should immediately begin
- * performance of the document given on the command line (if there is one).
- * "-autoQuit" indicates that TimeLine should quit immediately after
- * completion of performance of the document given on the command line.
- * The "-autoQuit" flag is only valid if "-autoPlay" is also specified.
- * These two options were added to support automated demos using TimeLine.
- *
- * Revision 1.14 92/10/01 14:49:52 drapeau
- * A number of minor changes were made to fix errors in the playback mechanism.
- * These errors were introduced when the "Synchronization Hints" feature was
- * added. The addition of this feature complicated the algorithm for
- * determining when it is appropriate to send OpenDocument, SetSelection,
- * PerformSelection, and other related messages to the applications comprising
- * a TimeLine document. Most of the error fixes had to do with testing for
- * boundary conditions.
- * Also, when the document has resumed playback (after it was previously put
- * into a Pause mode), TimeLine will now correctly change the status of the
- * document, returning it to PlayMode or PlaySelectedMode, whichever is
- * appropriate.
- * Several cosmetic changes were made to improve code readability and ANSI
- * compliance.
- *
- * Revision 1.13 92/09/29 18:02:21 drapeau
- * Modified TimerNotify(): modified a test that had previously failed to
- * test for a boundary condition.
- * Also, modified ResumeOrPerformSelections() to account for both complete
- * selections and partial selections. Mostly, it was a matter of taking the
- * current note's offset into account when deciding whether it was time to
- * perform a selection.
- * Also, made slight cosmetic changes in the code to improve readability.
- *
- * Revision 1.12 92/09/24 17:20:01 drapeau
- * Major changes have been made to this file, both to improve readability and to
- * implement synchronized documents.
- * The function most affected by the coding changes is the TimerNotify()
- * function, the workhorse of TimeLine's playback mechanism.
- * TimerNotify() now checks if the current document has synchronization
- * information; if so, the function schedules OpenDocument and SetSelection
- * messages according to the sync hints in each note to be played. If there is
- * no sync. information, TimerNotify will still schedule OpenDocument and
- * SetSelection messages correctly, but there will be delays as with the old
- * style documents.
- * In addition, if the author has chosen to generate sync hints, TimerNotify()
- * will note this and generate sync info for the document, then mark it as
- * modified.
- * TimerNotify() has been broken into several functions to make the code simpler
- * to read. Accordingly, comments have been updated to reflect the new
- * structure of the code.
- * The code now uses the new Sender method "SenderSynchronousMessaging()" to
- * implement the gathering and use of sync hints. During the gathering of
- * sync hints, and for documents with no sync hints, synchronous messaging is
- * used. This causes TimeLine to block on each note, waiting for completion of
- * each message sent to the media editors in a document. During playback of a
- * document that has sync hints, asynchronous messaging is used. In this case,
- * all messages sent by TimeLine return immediately, since the RPC's being sent
- * do not wait for replies from the media editors receiving those messages.
- * This enables TimeLine to schedule OpenDocument/SetSelection messages in
- * advance of the performance times for individual notes, thus helping achieve
- * documents that perform more closely to the wishes of authors. Ideally, such
- * documents are more "in sync" than documents with no sync hints.
- *
- * Other changes were made to the code to improve readability and ANSI
- * compliance.
- *
- * Revision 1.11 92/07/14 12:32:20 drapeau
- * Minor change to PlayStop() function: removed a feature that would
- * automatically quit the application when the end of a document was reached.
- * This feature was installed on request by an outside author, who wanted to
- * start TimeLine from the command line. In the future, this feature might
- * be added again, but with a command-line option to enable it.
- *
- * Revision 1.10 92/05/29 14:42:31 drapeau
- * Modified code to track new name of the MAEstro "Selection" structure;
- * it is now named "MAESelection".
- *
- * Revision 1.1 92/01/09 16:26:56 drapeau
- * Made slight modifications to make code more ANSI-compliant.
- *
- * Revision 1.0 91/09/30 17:02:28 chua
- * Update to version 1.0
- *
- * Revision 0.78 91/09/25 13:51:16 chua
- * Changed the instrument field, instInfo, to editInfo.
- * Changed InstrumentInfo to EditInfo.
- *
- * Revision 0.77 91/09/23 17:15:13 chua
- * Included a new function, Play, which is called when the play button is
- * pressed (the one with the icon). If the TimeLine is in play mode, pressing
- * this button has no effect. If the TimeLine is in pause mode, pressing
- * this button will resume play. If the TimeLine is in stop mode, pressing
- * this button will play selected region, or from insertion point, or
- * whole document (in order of priority).
- *
- * PlayStop is now only called when we actually want to stop the timer
- * completely (when TimeLine is in stop mode). During pause, the timer
- * continues functioning.
- *
- * In TimerNotify, check every second to see if either the pause or play
- * button needs to have their color changed. Also, if the TimeLine is
- * in pause mode, simply update the virtual clock and exit. Do not check
- * if notes need to be played.
- *
- * Revision 0.76 91/09/20 15:03:47 chua
- * Added calls to BusyCursor and NormalCursor to change the cursor type when
- * doing OpenDoc and SetSelection.
- *
- * Revision 0.75 91/09/19 17:29:03 chua
- * Make sure that variables are initialized properly. Change formatting slightly,
- * so that (if, for, while) statements with only one statement in them will not have
- * braces.
- *
- * Revision 0.74 91/08/26 16:38:05 chua
- * In TimerNotify, if a pause has been detected, exit from the notify procedure.
- *
- * Revision 0.73 91/08/21 16:59:45 chua
- * In TimerNotify and PreLoad, if SetSelection does not return 0, do a number of Ping
- * commands (determined by the constant PingTimes) to allow the app time to do the
- * set selection.
- *
- * Revision 0.72 91/08/20 16:18:41 chua
- * Declare startApp and numApps as globals to make them visible to the functions in
- * stop.c
- *
- * In TimerNotify (line 413), a check is made to see that CheckAppOpen returns OK.
- *
- * Revision 0.71 91/08/19 19:21:02 chua
- * In TimerNotify, set the currentNote pointer to point to where the current note is,
- * so that resume will work properly.
- *
- * Revision 0.70 91/08/16 17:03:06 chua
- * Made changes to the comments header for TimerNotify. Also, removed the gettimeofday
- * variables and the function AllocateTimerSpace as these are no longer needed.
- *
- * Moved the DrawPlaybackHead routine to drawCanvas.c
- *
- * Add a new function, PreLoad, which will do a OpenDoc and SetSelection message call
- * for the first notes that are to be played, when a play operation is in progress.
- *
- * Moved the StopHandler and PauseResumeHandler to stop.c
- *
- * Revision 0.69 91/08/14 12:13:07 chua
- * Added a new function PreLoad, which will do a OpenDoc and SetSelection for the first notes
- * in each application during the start of a play operation.
- *
- * Do the necessary modifications in TimerNotify to support the above. (involves testing if the
- * note is not the first one before doing the OpenDoc and SetSelection).
- *
- * Revision 0.68 91/08/08 15:15:24 chua
- * In TimerNotify, before doing a OpenDoc and SetSelection, check that the
- * application is open first.
- *
- * Revision 0.67 91/08/08 14:28:48 chua
- * Before a play operation, if the applications are not muted, check that they are all
- * still open before proceeding. This is done by trying to create a new sender with each
- * application.
- *
- * Also, in the areas where there are network messages sent, such as Pause, Halt, etc,
- * do not send the messages if the application is muted.
- *
- * Revision 0.66 91/08/05 16:53:30 chua
- * Deleted the RepaintCanvas routine, as it is no longer necessary. In places where it
- * is called, just call the ScrollToFirstQuarter routine, which will do the necessary
- * repaint as well.
- *
- * Revision 0.65 91/08/05 14:40:33 chua
- * In the PlayHandler, PlayFromHandler and PlaySelectedHandler, a check is made to see that
- * the applications are still alive before attempting to play. This is done by trying to
- * create a sender to the application. If the NewSender call returns a NULL, then the
- * application is no longer alive and the play operation is aborted.
- *
- * Revision 0.64 91/08/05 13:05:34 chua
- * In the PlayHandler and PlayFromPoint routine, call the ScrollToFirstQuarter routine to check if
- * the canvas needs to be scrolled, so that the playback head will be visible.
- *
- * Revision 0.63 91/07/22 15:22:31 chua
- * In the TimerNotify, also check the pause list to see if a pause marker exist at the
- * current time. If so, call the PauseResumeHandler to pause the applications.
- *
- * Revision 0.62 91/07/17 16:35:00 chua
- * Reformatted the braces for the switch statements.
- *
- * Revision 0.61 91/07/17 10:34:58 chua
- * The definition of the playback head position, lastX, has been changed. It now
- * indicates its position in terms of pixel value at the lowest zoom level.
- * So code where lastX or the DrawPlaybackHead function is called will have some
- * changes to accomodate this change.
- *
- * In the TimerNotify procedure, check if we need to remap the canvas while playing.
- *
- * In the DrawPlaybackHead procedure, check that the playback head is in the current
- * canvas before drawing it.
- *
- * Revision 0.60 91/07/09 18:25:05 chua
- * Made changes to the startX, endX variables so that they now store the position at the
- * largest zoom level (zoom level = 1). Thus, the appropriate multiplication or
- * division by the zoom level has to be made when these variables are used. This will
- * include lastX (position of the playback head) as well.
- *
- * Revision 0.59 91/07/09 17:02:41 chua
- * Removed a redundant variable.
- *
- * Revision 0.58 91/07/01 11:02:37 chua
- * Changed PlayFromHandler so that if playback head is not present, it is set to zero.
- * The reason this is done is because the default selection in the play menu button is
- * now "Play from insertion point".
- *
- * Revision 0.57 91/06/28 17:26:47 chua
- * Changed a line in TimerNotify so that OpenDoc and SetSelection gets
- * called when playing from the middle of a segment.
- *
- * Revision 0.56 91/06/27 14:16:55 chua
- * Changed a line in TimerNotify, so that as long as note->start is the same as the
- * virtualClock, the TimeLine Editor will send OpenDoc and SetSelection messages to the
- * application.
- *
- * Revision 0.55 91/06/27 11:51:12 chua
- * Modified the play and pause/resume handlers to correctly set the mode. Resume will now
- * work correctly.
- *
- * Revision 0.54 91/06/26 16:47:17 chua
- * Added code to handle zooming and also the new protocol items, which are playing partial
- * selections, pause selection, halt selection and resume selection.
- * Refer to the comment headings within the code for more details.
- *
- * Revision 0.53 91/06/04 17:37:26 chua
- * Added the copyright comments in the beginning of the file.
- *
- * Revision 0.52 91/06/03 11:12:04 chua
- * Make changes to accomodate multiple documents. This involves identifying
- * which is the current active window, that is, the one where the last mouse
- * click was done.
- *
- * Revision 0.51 91/05/29 14:42:52 chua
- * In the TimerNotify procedure (lines 196-199), check to see that the instrument is not muted
- * before procedure to make the message calls to the remote application.
- *
- * Also, in the play and stop procedures, include the function call to DimButtons to dim/undim
- * the buttons during playback or stop mode. The dimming of buttons is to prevent errors, such as
- * the user trying to cut some section of the TimeLine while it is playing.
- *
- * Revision 0.50 91/05/24 16:37:51 chua
- *
- *
- * Revision 0.49 91/05/23 17:39:10 chua
- * *** empty log message ***
- *
- * Revision 0.48 91/05/22 16:42:06 chua
- * Removed the CheckIfNoteSelected function call in the PlaySelectedHandler routine.
- *
- * Revision 0.47 91/05/22 13:59:39 chua
- * In the PlaySelectedHandler routine, replace the if (startX != endX) statement with
- * if (areaSelected || noteSelected). The latter is a more correct way of checking if either
- * a note or a region is selected.
- *
- * Revision 0.46 91/05/22 11:47:22 chua
- * In the PlaySelectedHandler, first check if a note is selected. Next, instead of checking
- * if the areaSelected variable is set, check for whether startX != endX, an indication that
- * either an area is selected or a note is selected.
- *
- * The changes enables the play selected menu to play a selected note as well.
- *
- * Revision 0.45 91/05/17 16:57:21 chua
- * *** empty log message ***
- *
- * Revision 0.44 91/05/17 16:41:26 chua
- * Added code to enable the TLE to play a selected region. This region need not include all open
- * applications and the TLE will just play those applications that have been selected.
- *
- * In the TimerNotify procedure, instead of using a while loop to go through all the instruments
- * when testing which instrument has a note to be played, a for-loop is now used so that only
- * the instruments selected (which must be sequential, by virtual of the selection paradigm) will
- * be tested. For the play all and play from insertion point functions, this for-loop will
- * essentially be the same as the while loop, since all instruments will be tested.
- * For the PlaySelected procedure, the parameters startApp and numApps are used to control the
- * for-loop. This are obtained by performing some calculations on the startY and endY variables
- * set in the DrawCanvasEventHandler. The calculations are done in the PlaySelectedHandler
- * function.
- *
- * Besides filling in the code for the PlaySelectedHandler, a new function, PlayFromPoint is
- * introduced. The reason is the PlayFromHandler and the PlaySelectedHandler share similar
- * initialization routines, such as testing if scrolling is necessary, initializing the timer etc.
- * So just one function is created instead of duplicating code in both places.
- *
- * Revision 0.43 91/05/16 15:20:54 chua
- * Added a new menu function to the play button: Play the selected region (PlaySelectedHandler).
- * Functionality not implemented yet.
- *
- * Revision 0.42 1991/05/15 02:58:36 chua
- * In the PlayStop function, instead of setting all the timer values to zero and calling the
- * timer notify function again, replace the parameters in the notify_set_itimer_func call
- * to NOTIFY_FUNC_NULL and NULL in place of NULL and &timer. This will have the same effect
- * of turning the timer off and takes only one line of code instead of several!
- *
- * Also, in the timer notify function, when calculating the timediff, change the statement
- * timediff = timediff/100000 to timediff = (timediff + 50000) / 100000
- *
- * This has the more accurate result of rounding rather than truncating the calculated time,
- * though probably it doesn't really matter, with the larger synchronization problems caused
- * by the slower media.
- *
- * Revision 0.41 1991/04/24 01:12:30 chua
- * *** empty log message ***
- *
- * Revision 0.40 1991/04/01 03:51:30 chua
- * This file contains the timer notify function to perform playback of a timeline document and also the
- * menu handlers for the play menu button. The functions are:
- * AllocateTimerSpace - allocate memory for the timer variables used to keep track of real time.
- * TimerNotify - Timer notify routine which does the playback of a TimeLine document.
- * PlayHandler - Menu handler for the play menu selection. Plays from the start of a document.
- * PlayStop - Routine to turn off the timer, thus stopping play and free the timer variables.
- * Stop - Button notify procedure for the Stop button which sets the status flag to StopMode, which will be
- * detected by the TimerNotify routine and causing PlayStop to be called.
- * PlayFromHandler - Menu handler for the play from menu selection. Plays from where the playback head is.
- * DrawPlaybackHead - Draws the playback head at the new position and erase the old one.
- * */
-
- #include "main.h"
-
- static char Playrcsid[] = "$Header: /Source/Media/collab/TimeLine/RCS/play.c,v 1.16 92/10/30 16:22:49 drapeau Exp $";
-
- int startApp; /* The starting application to be played during playback */
- int numApps; /* The number of applications to be played during playback */
- static long virtualClock; /* A simple 'clock' maintained by this application. It... */
- /* ...keeps track of the current position of the... */
- /* ...playback head during playback. The XView timer... */
- /* ...notify function is used to periodically... */
- /* ...(1/10th of a second) call a function that advances... */
- /* ...the playback head */
- static TimeLineFramePtr currenttlFrame; /* Pointer to current TimeLine document being played */
- static struct itimerval timer; /* Timer for playback purposes */
- static long canvasWidth; /* Current width of the canvas window. This information... */
- /* ...is used to facilitate scrolling of the canvas... */
- /* ...during playback. */
- static long canvasStart; /* Current start point of the canvas in the window. */
- static long endTime; /* Estimated ending time of current document in playback. */
- static long endSelectedTime; /* The end time for a selected region */
- static int status = StopMode;
- static int flag = 0; /* Indicates what color is to be drawn for the play button */
-
- /*
- * This function checks if the playback head is at a pause marker during
- * playback. The donePause variable is necessary, because after we
- * resume from a pause, the playback head will still be at the same
- * position. So we compare this with the donePause and if they are the
- * same, ignore the pause marker.
- */
- int CheckPause()
- {
- Pause *pause;
- int found;
-
- pause = currenttlFrame->pauseHead; /* Check if there is a pause */
- found = 0;
- while (pause != NULL && !found)
- {
- if (pause->position == virtualClock)
- {
- if (pause == currenttlFrame->donePause) /* Make sure this pause marker is not the old one */
- currenttlFrame->donePause = NULL;
- else
- {
- found = 1;
- currenttlFrame->donePause = pause;
- PauseResume(currenttlFrame->TimeLine_window->pauseButton, NULL);
- return OK;
- }
- }
- pause = pause->next;
- }
- return Error; /* No pause marker found */
- } /* end function CheckPause */
-
-
- /*
- * This is the timer notify function that is called by the XView
- * timer notify procedure. It is called every 1/10th of a second during
- * playback, regardless of the zoom level. This way, the playback of
- * notes will be accurate regardless of the zoom level.
- *
- * First, BlinkPlayButton() is called to do just that.
- *
- * Next, UpdatePlaybackHead() is called to redraw the playback head
- * and canvas, if necessary.
- *
- * Next, check if we are at a pause marker, done by calling the
- * CheckPause routine.
- *
- * The function next goes through the instrument list one by one.
- * Each instrument has a current note pointer which indicates which note
- * is currently being accessed. Note that only the instruments selected
- * will be tested for whether there is a note to be played.
- * The FindNextNoteToPerform() function is called to determine if the
- * current instrument has a note to set up for performance.
- *
- * A finished flag is used to determine if there are any more notes to
- * be processed. This flag is set to 1 initially before the loop to test
- * if any notes are to be played. If all the instrument's current note
- * pointer is NULL, this means no more notes need to be played and the
- * flag remains at 1. Otherwise, the finished flag is set to 0.
- *
- * If such a note is found, the function determines whether it is time
- * to prepare the note for performance. If so, the function
- * PrepareNoteForPerformance() is called. If the virtualClock is in the
- * middle of a note and this TimeLine document is in one of the Resume
- * modes, then instead of preparing the current note for performance, a
- * flag is set to indicate that a ResumeSelection message should be sent
- * at the appropriate time, instead of a PerformSelection message.
- *
- * This testing and performance preparation is done for all instruments
- * before calling the SenderPerformSelection. The purpose is to have all
- * the applications do their seeking first so that they are ready to play
- * at about the same time.
- *
- * If the current instrument has a note ready to play, the playNote
- * flag of that instrument is then set to 1, indicating that this
- * instrument now has a note to be played. The endTime variable is also
- * updated if necessary, that is, if the end time of the note to be
- * played is later than the current end time.
- *
- * After all of the instruments have been scanned for ready-to-play
- * notes, the function ResumeOrPerformSelections() is called. The
- * function will take care of the actual performance of notes at the
- * correct time. If a document has synchronization hints, it will often
- * be the case that the times for Preparing a selection for performance
- * and actually Performing the selection will differ.
- *
- *
- * After all preparation and performance work is done, a check is made to
- * determine if:
- * 1) the stop button has been pressed;
- * 2) the virtualClock time is greater than the endTime and finished is
- * set to 1, meaning no more notes to be played (the endTime variable is
- * necessary so that the playback head will continue moving to the end of
- * the last note);
- * 3) the virtualClock has reached the end of a selected region, denoted
- * by the "endSelectedTime" variable, which is set when the playSelected
- * button is chosen.
- * If either of the above 3 conditions are satisfied, play will be
- * halted.
- */
-
- Notify_value TimerNotify()
- {
- int i;
- int finished;
- int startTime = 0;
- Instrument* instrument;
-
- BlinkPlayButton(); /* Determine whether to change the color of the Play button */
- if (currenttlFrame->status == PauseMode || /* Do not update time if in pause mode */
- currenttlFrame->status == PauseSelectedMode)
- {
- virtualClock ++;
- return NOTIFY_DONE;
- }
- UpdatePlaybackHead(); /* Determine whether playback head needs to be redrawn */
- if (CheckPause() == OK) /* Pause marker located. Do not continue. */
- return NOTIFY_DONE;
- instrument = (Instrument *) FindInstrument(startApp, currenttlFrame);
- finished = 1;
- for (i=0; i < numApps; i++, instrument = instrument->next) /* Looking at one instrument at a time, do the following: */
- {
- if (xv_get(instrument->editInfo->MuteChoice, PANEL_VALUE) == 1) /* If this instrument is muted, don't bother doing work... */
- continue; /* ...on it; just go on to the next instrument on the list. */
- if (FindNextNoteToPerform(instrument) == (Note*)NULL) /* Is there a note to perform right now for this instrument? */
- continue; /* No, go on to the next instrument */
- startTime = CalculateStartTime(instrument); /* Get start time for this note */
- finished = 0;
- if (startTime == virtualClock || /* Is it time to do something? Test 1 determines whether...*/
- (instrument->currentNote->start <= virtualClock && /* ...OpenDoc/SetSelection are to be called; Tests 2 & 3... */
- instrument->currentNote->end > virtualClock)) /* ...determine if clock is in the middle of a note */
- {
- UpdateEndTime(instrument); /* Update the global variable "endTime" if necessary */
- if (startTime == virtualClock)
- instrument->currentNote->ms->selection->offset = 0; /* No offset; playing a complete selection */
- else
- instrument->currentNote->ms->selection->offset = /* Calculate the offset for a partial selection */
- (virtualClock - instrument->currentNote->start) * 100;
- if (startTime == virtualClock || /* It's time to send OpenDoc & SetSelection messages so... */
- (currenttlFrame->status != ResumeMode && /* ...PerformSelection can execute immediately. Also,... */
- currenttlFrame->status != ResumeSelectedMode)) /* ...TimeLine should not perform a ResumeSelection here. */
- {
- PrepareNoteForPerformance(instrument, startTime);
- } /* end if(startTime == virtualClock...) */
- if (startTime != virtualClock && /* Resume selection is to be done, not perform selection */
- (instrument->currentNote->start != virtualClock) &&
- (currenttlFrame->status == ResumeMode ||
- currenttlFrame->status == ResumeSelectedMode))
- instrument->partialNote = 1;
- } /* end if (startTime == virtualClock...) */
- } /* end for... */
- ResumeOrPerformSelections();
- if ((virtualClock >= endTime && finished) ||
- currenttlFrame->status == StopMode) /* No more notes to be played or stop has been pressed */
- {
- UpdateSyncHints(finished); /* Update synchronization hints for this doc, if necessary */
- PlayStop(); /* Regardless, stop playing the document. */
- }
- else if (virtualClock >= endSelectedTime && /* Reached the end of a selected region */
- (currenttlFrame->status == PlaySelectedMode ||
- currenttlFrame->status == ResumeSelectedMode))
- {
- StopPlayingSelection();
- }
- else
- virtualClock ++; /* Increment the clock counter */
- return NOTIFY_DONE;
- } /* end function TimerNotify */
-
-
- /*
- * Function to turn off the timer and stop playback.
- * Called by TimerNotify (play.c)
- */
- void PlayStop()
- {
- int i;
- Instrument* instrument;
-
- notify_set_itimer_func(currenttlFrame->TimeLine_window->window, /* Turn timer off */
- NOTIFY_FUNC_NULL, ITIMER_REAL,
- NULL, NULL);
- if ((autoQuit == True) && (autoPlay == True)) /* Was a command-line option set to quit TL immediately... */
- xv_destroy_safe(currenttlFrame->TimeLine_window->window); /* ...after the document was performed? If so, quit. */
- DimButtons(FALSE, currenttlFrame);
- currenttlFrame->donePause = NULL;
- status = StopMode;
- currenttlFrame->status = StopMode;
- instrument = (Instrument *) FindInstrument(startApp, currenttlFrame);
- for (i=0; i < numApps; i++) /* Restore synchronous messaging, so that TimeLine will... */
- { /* ...block waiting for completion of messages. */
- SenderSynchronousMessaging(instrument->sender, On);
- instrument = instrument->next;
- }
- xv_set(currenttlFrame->TimeLine_window->playIconButton,
- PANEL_ITEM_COLOR, gcm_color_index("black"), NULL);
- xv_set(currenttlFrame->TimeLine_window->pauseButton,
- PANEL_ITEM_COLOR, gcm_color_index("black"), NULL);
- } /* end function PlayStop */
-
-
- /* This function is called before a play operation. It will ask all
- * the relevant applications to preload their documents and perform a
- * seek (if applicable) first.
- */
-
- void PreLoad()
- {
- Instrument* instrument;
- int i, done;
- int result;
- int count;
-
- BusyCursor(currenttlFrame);
- instrument = (Instrument *) FindInstrument(startApp, currenttlFrame);
- for (i=0; i < numApps; i++) /* Check to see which notes need to be played... */
- { /* ...currently. If such a note is found, do an... */
- done = 0; /* ...open doc and set selection function first */
- while (instrument->currentNote != NULL && !done) /* Either go through the whole instrument list or a... */
- { /* ...subset of it, depending on startApp and numApps values */
- if (instrument->currentNote->start < virtualClock &&
- instrument->currentNote->end <= virtualClock) /* Keep searching while whole note is before virtual clock. */
- instrument->currentNote = instrument->currentNote->next;
- else
- done = 1;
- }
- if (instrument->currentNote != NULL)
- {
- if (virtualClock < instrument->currentNote->start)
- instrument->currentNote->ms->selection->offset = 0;
- else
- instrument->currentNote->ms->selection->offset = /* Calculate the offset */
- (virtualClock - instrument->currentNote->start) * 100;
- if (xv_get(instrument->editInfo->MuteChoice, PANEL_VALUE) == 0)
- {
- if (CheckAppOpen(currenttlFrame, instrument, 0) == OK) /* If app is no longer open, error message appears... */
- { /* ...and the app is muted */
- InstrumentDrawIcon(instrument, Waiting, currenttlFrame); /* Redraw the icon with a red background */
- XFlush((Display*)xv_get(currenttlFrame->TimeLine_window->window, XV_DISPLAY));
- SenderSynchronousMessaging(instrument->sender, On); /* Make sure that OpenDoc and SetSelection messages block... */
- SenderOpenDocument (instrument->sender, /* ...until completion */
- instrument->currentNote->ms->documentName);
- result = SenderSetSelection (instrument->sender,
- instrument->currentNote->ms->selection);
- count = 0;
- while (result != 0 && count < PingTimes)
- {
- result = SenderPing(instrument->sender);
- count ++;
- }
- if (currenttlFrame->syncHints == SyncHintsAvailable) /* If synchronization information is present, make sure... */
- SenderSynchronousMessaging(instrument->sender, Off); /* ...that each Sender is sending messages asynchronously */
- else /* If not, make sure that each Sender is blocking for... */
- SenderSynchronousMessaging(instrument->sender, On); /* ...events like OpenDoc, Set/PerformSelection to finish */
- if (instrument->relativePosition == currenttlFrame->chosenApp) /* Redraw the icon as it was originally */
- InstrumentDrawIcon(instrument, Sunken, currenttlFrame);
- else
- InstrumentDrawIcon(instrument, Raised, currenttlFrame);
- XFlush((Display*)xv_get(currenttlFrame->TimeLine_window->window, XV_DISPLAY));
- }
- }
- }
- instrument = instrument->next;
- }
- NormalCursor(currenttlFrame);
- } /* end function PreLoad */
-
- /*
- * Menu handler for `PlayMenu (Play)'
- * This function will initiate the playback routine, starting play from
- * the beginning of the document.
- * 1) Sets all the current note pointer of each instrument to point to
- * the first note of each instrument. It then checks if all applications
- * are still open by attempting to create a new sender.
- * 2) Resets the starting position of the canvas to the start of the
- * document.
- * 3) Get the width of the canvas window. This is for scrolling
- * purposes, to be used by the TimerNotify procedure.
- * 4) Initialize the canvasStart, endTime and virtualClock variables,
- * and allocate space for the real time variables.
- * 5) Dim the buttons (so that only the Stop button is active).
- * 6) Set the status to PlayMode, initialize the timer values and call
- * the XView timer notify function. This function will call the
- * specified TimerNotify function once every 1/10th of a second.
- */
- Menu_item PlayHandler(Menu_item item, Menu_generate op)
- {
- Instrument* instrument;
- TimeLineFramePtr tlFrame;
- TimeLine_window_objects* ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
-
- if (status == StopMode)
- {
- tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
- currenttlFrame = tlFrame;
- switch (op)
- {
- case MENU_DISPLAY:
- break;
- case MENU_DISPLAY_DONE:
- break;
- case MENU_NOTIFY:
- instrument = tlFrame->instHead; /* Set current note of each instrument to point to 1st note */
- while (instrument != NULL) /* Also check that all applications are still alive */
- {
- instrument->currentNote = instrument->firstNote;
- if (CheckAppOpen(tlFrame, instrument, 0) == Error) /* Check if the application is alive */
- return item;
- instrument->initialNote = 1;
- instrument = instrument->next;
- }
- ScrollToFirstQuarter(tlFrame, 0, 0); /* Scroll to make the start of the document visible */
- canvasWidth = xv_get(tlFrame->DrawScrollbarHor, /* Get the width of the canvas, for scrolling purposes */
- SCROLLBAR_VIEW_LENGTH);
- tlFrame->status = PlayMode; /* Set the status to PlayMode */
- status = PlayMode;
- canvasStart = 0; /* Initialize the playback variables */
- endTime = -1;
- virtualClock = 0;
- startApp = 0; /* Indicate starting and # of apps. Since we are playing... */
- numApps = tlFrame->numberOfApps; /* ...all apps, start app is 0, numApps is all the apps open */
- DimButtons(TRUE, tlFrame);
- PreLoad();
- timer.it_value.tv_sec = 0; /* Set the timer values to notify every 1/10th of a second */
- timer.it_value.tv_usec = 100000; /* TimerNotify() will take care of the actual playback */
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 100000;
- notify_set_itimer_func(tlFrame->TimeLine_window->window,
- TimerNotify, ITIMER_REAL,
- &timer, NULL);
- break;
- case MENU_NOTIFY_DONE:
- break;
- }
- }
- return item;
- } /* end function PlayHandler */
-
- /*
- * This function performs the initialization necessary to begin play
- * from a certain point on the timeline, whether it is from the insertion
- * point (playback head) or from the start of a selected region.
- *
- * 1) Get the current starting position of the canvas and the width of
- * the canvas window. These are used for scrolling purposes by the
- * TimerNotify procedure. If the starting position is currently not
- * visible on the canvas, scroll the canvas such that the starting
- * position is visible.
- * 2) Sets the current note pointer of each instrument to point to
- * the first note of each instrument. The TimerNotify procedure will
- * take care of advancing the current note pointer to the next note
- * closest to the playback head.
- * 3) Set the status to PlayMode, initialize the timer values and call
- * the XView timer notify function. This function will call the
- * specified TimerNotify function once every 1/10th of a second.
- *
- * Called by PlayFromHandler and PlaySelectedHandler (play.c)
- */
-
- void PlayFromPoint(TimeLineFramePtr tlFrame)
- {
- Instrument* instrument;
-
- currenttlFrame = tlFrame;
- ScrollToFirstQuarter(tlFrame, tlFrame->lastX, 0); /* Scroll to make the playback head visible */
- canvasStart = xv_get(tlFrame->DrawScrollbarHor, /* Get the current starting position of the canvas */
- SCROLLBAR_VIEW_START);
- canvasWidth = xv_get(tlFrame->DrawScrollbarHor, /* Get the width of the canvas, for scrolling purposes */
- SCROLLBAR_VIEW_LENGTH);
- instrument = tlFrame->instHead; /* Set current note of each instrument to point to 1st note */
- while (instrument != NULL)
- {
- if (tlFrame->status != ResumeMode && tlFrame->status != ResumeSelectedMode)
- {
- instrument->currentNote = instrument->firstNote;
- instrument->initialNote = 1;
- }
- instrument = instrument->next;
- }
- DimButtons(TRUE, tlFrame);
- if (tlFrame->status != ResumeMode && tlFrame->status != ResumeSelectedMode)
- PreLoad();
- timer.it_value.tv_sec = 0; /* Set the timer values to notify every 1/10th of a second */
- timer.it_value.tv_usec = 100000; /* The TimerNotify function will take care of playback */
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 100000;
- notify_set_itimer_func(tlFrame->TimeLine_window->window, TimerNotify, ITIMER_REAL,
- &timer, NULL);
- }
-
-
-
- /*
- * Menu handler for `PlayMenu (play from)'
- * This function will initiate the playback routine, starting play from
- * where the playback head is. It first checks if all applications are
- * still open by attempting to create a new sender. It initializes the
- * start (virtualClock) and end (endTime) times and calls PlayFromPoint
- * to do the other initializations and initiate playing.
- */
-
- Menu_item PlayFromHandler(Menu_item item,
- Menu_generate op)
- {
- Instrument* instrument;
- TimeLineFramePtr tlFrame;
- TimeLine_window_objects* ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
-
- tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
- if (status == StopMode || tlFrame->status == ResumeMode)
- {
- switch (op)
- {
- case MENU_DISPLAY:
- break;
- case MENU_DISPLAY_DONE:
- break;
- case MENU_NOTIFY:
- instrument = tlFrame->instHead; /* Set current note of each instrument to point to 1st note */
- while (instrument != NULL) /* Also check that all applications are still alive */
- {
- if (CheckAppOpen(tlFrame, instrument, 0) == Error) /* Check if the application is alive */
- return item;
- instrument = instrument->next;
- }
- if (tlFrame->lastX == -1) /* Set playback head to start position if it's not on canvas */
- tlFrame->lastX = 0;
- virtualClock = tlFrame->lastX; /* Set starting point to where the playback head is */
- endTime = -1;
- if (tlFrame->status != ResumeMode)
- tlFrame->status = PlayMode; /* Set the status to PlayMode only if not in ResumeMode */
- status = PlayMode;
- startApp = 0; /* Indicate starting and # of apps. Since we are playing... */
- numApps = tlFrame->numberOfApps; /* ...all apps, start app is 0 & numApps is all apps open */
- PlayFromPoint(tlFrame);
- break;
- case MENU_NOTIFY_DONE:
- break;
- }
- }
- return item;
- } /* end function PlayFromHandler */
-
-
-
- /*
- * Menu handler for `PlayMenu (Play selected area)'.
- * This function will play the selected area on the timeline. It will
- * only play those instruments which are in the selected area. If no
- * area is selected, nothing happens. Before playing, it will also check
- * to see that all the applications that are in the selected area are
- * still alive.
- */
-
- Menu_item PlaySelectedHandler(Menu_item item,
- Menu_generate op)
- {
- int i;
- Instrument* instrument;
- TimeLineFramePtr tlFrame;
- TimeLine_window_objects* ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
-
- tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
- if (status == StopMode || tlFrame->status == ResumeSelectedMode)
- {
- switch (op)
- {
- case MENU_DISPLAY:
- break;
- case MENU_DISPLAY_DONE:
- break;
- case MENU_NOTIFY:
- startApp = tlFrame->startY / (IconHeight + IconGap); /* Determine which instruments are selected */
- numApps = tlFrame->endY / (IconHeight + IconGap) - startApp;
- instrument = (Instrument *) FindInstrument(startApp, tlFrame);
- for (i=0; i < numApps; i++)
- {
- if (CheckAppOpen(tlFrame, instrument, 0) == Error) /* Check if the application is alive */
- return item;
- instrument = instrument->next;
- }
- if (tlFrame->areaSelected || tlFrame->noteSelected)
- {
- if (tlFrame->status != ResumeSelectedMode)
- {
- tlFrame->status = PlaySelectedMode;
- DrawPlaybackHead(tlFrame->startX, tlFrame);
- }
- virtualClock = tlFrame->lastX * tlFrame->zoomLevel; /* Set starting point to where the playback head is */
- endSelectedTime = tlFrame->endX * tlFrame->zoomLevel;
- endTime = virtualClock;
- status = PlaySelectedMode;
- PlayFromPoint(tlFrame);
- }
- break;
- case MENU_NOTIFY_DONE:
- break;
- }
- }
- return item;
- } /* end function PlaySelectedHandler */
-
-
-
- /*
- * Notify callback function for `playIconButton'.
- * If a note or region has been selected, do a play selected region/note. Else, play from insertion point.
- */
- void Play(item, event)
- Panel_item item;
- Event *event;
- {
- TimeLineFramePtr tlFrame;
- TimeLine_window_objects *ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
-
- tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
- if (tlFrame->status == PauseMode || tlFrame->status == PauseSelectedMode)
- PauseResume(item, event);
- else if (tlFrame->status == StopMode)
- {
- if (tlFrame->areaSelected == 1 || tlFrame->noteSelected == 1)
- PlaySelectedHandler(item, MENU_NOTIFY);
- else
- PlayFromHandler(item, MENU_NOTIFY);
- }
- }
-
-
-
- /*
- * Menu handler for `PlayMenu (Synchronize This Document)'.
- */
- Menu_item
- SynchronizeDocument(Menu_item item, Menu_generate op)
- {
- TimeLineFramePtr tlFrame;
- TimeLine_window_objects *ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
-
- tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
- switch (op)
- {
- case MENU_DISPLAY:
- break;
-
- case MENU_DISPLAY_DONE:
- break;
-
- case MENU_NOTIFY:
- tlFrame->syncHints = GeneratingSyncHints; /* Set flag saying that sync hints should be generated */
- PlayHandler(item, op); /* Begin playback of document & calculate sync hints */
-
- /* gxv_start_connections DO NOT EDIT THIS SECTION */
-
- /* gxv_end_connections */
-
- break;
-
- case MENU_NOTIFY_DONE:
- break;
- }
- return item;
- } /* end function SynchronizeDocument */
-
-
-
- void BlinkPlayButton() /* Determines what color to make the Play button; alternates... */
- { /* ...between green and black */
- if (virtualClock % PixelsPerSecond == 0) /* Is it time to determine whether to change colors? */
- { /* Yes, toggle the color of the Play button */
- if (currenttlFrame->status != StopMode && flag) /* Highlight the play button in green or black (alternating) */
- {
- xv_set(currenttlFrame->TimeLine_window->playIconButton,
- PANEL_ITEM_COLOR, gcm_color_index("green"), NULL);
- if (currenttlFrame->status != PauseMode &&
- currenttlFrame->status != PauseSelectedMode)
- {
- xv_set(currenttlFrame->TimeLine_window->pauseButton,
- PANEL_ITEM_COLOR, gcm_color_index("black"), NULL);
- }
- flag = 0;
- }
- else if (currenttlFrame->status == PauseMode ||
- currenttlFrame->status == PauseSelectedMode)
- {
- xv_set(currenttlFrame->TimeLine_window->playIconButton,
- PANEL_ITEM_COLOR, gcm_color_index("black"), NULL);
- xv_set(currenttlFrame->TimeLine_window->pauseButton,
- PANEL_ITEM_COLOR, gcm_color_index("green"), NULL);
- if (flag)
- flag = 0;
- else
- flag = 1;
- }
- else
- {
- xv_set(currenttlFrame->TimeLine_window->playIconButton,
- PANEL_ITEM_COLOR, gcm_color_index("black"), NULL);
- xv_set(currenttlFrame->TimeLine_window->pauseButton,
- PANEL_ITEM_COLOR, gcm_color_index("black"), NULL);
- flag = 1;
- }
- }
- } /* end function BlinkPlayButton */
-
-
-
- /* UpdatePlaybackHead() -- A function to redraw the the playback head
- * and the TimeLine canvas.
- * This functions checks if time has passed by a pixel's equivalent
- * (depending on the zoom level). If so, it does the following:
- * - Draw the playback head at the new position.
- * - Check if scrolling is necessary. When the playback head
- * reaches 50 pixels from the end of the viewing window, the canvas will
- * scroll a 'page' and the playback head will be repositioned
- * about 100 pixels from the start of the window. This is to allow the
- * user to see what was going on before the scrolling point. If
- * necessary, the canvas will be remapped to the next segment of the
- * timeline, if the playback head is near the end of the canvas.
- */
-
- void UpdatePlaybackHead() /* Determines if it's time to redraw the playback head */
- {
- if (virtualClock % currenttlFrame->zoomLevel == 0) /* Only redraw the playback head when it has moved 1 pixel */
- {
- DrawPlaybackHead(virtualClock, currenttlFrame); /* Draw the playback head */
- if ((currenttlFrame->lastX / currenttlFrame->zoomLevel) -
- currenttlFrame->canvasStart >=
- (canvasStart + canvasWidth - (PixelsPerSecond * 5))) /* Check if scrolling is necessary */
- {
- canvasStart = (currenttlFrame->lastX / currenttlFrame->zoomLevel) /* 100 pixels spacing from the start of the canvas... */
- - (PixelsPerSecond * 10); /* ...to the playback head */
- if (canvasStart > /* Check if the canvas start is beyond the last... */
- currenttlFrame->TimeLineLength - canvasWidth) /* ...viewing window of the canvas. If so, switch to the... */
- { /* ...next segment of the TimeLine document */
- currenttlFrame->canvasStart = currenttlFrame->lastX -
- (PixelsPerSecond * 10 / currenttlFrame->zoomLevel);
- currenttlFrame->canvasStart = currenttlFrame->canvasStart -
- currenttlFrame->canvasStart % (TimeLineInterval * PixelsPerSecond)
- + (TimeLineInterval * PixelsPerSecond);
- canvasStart = 1;
- ShowNewCanvas(currenttlFrame, 1);
- }
- else
- xv_set(currenttlFrame->DrawScrollbarHor, SCROLLBAR_VIEW_START,
- canvasStart, NULL);
- }
- }
- } /* end function UpdatePlaybackHead */
-
-
-
- void PrepareNoteForPerformance(Instrument* instrument, int startTime)
- {
- int result = 0;
- int count = 0;
- int elapsedTime = 0;
- struct timeval before, after;
-
- if (instrument->initialNote == 1) /* Do not seek again if it is the first note to be played. */
- {
- instrument->initialNote = 0;
- instrument->playNote = 1; /* Set flag so PerformSelection should be done for this note */
- return;
- }
- if (startTime != virtualClock) /* Is it really time to send the OpenDoc and SetSelection... */
- return; /* ...messages? If not, return without doing anything*/
- BusyCursor(currenttlFrame);
- if (currenttlFrame->syncHints == GeneratingSyncHints) /* Should synchronization hints be calculated? */
- result = gettimeofday(&before,(struct timezone*)NULL); /* Yes, get time before calling OpenDoc & SetSelection... */
- if (CheckAppOpen(currenttlFrame, instrument, 0) != OK) /* If app is no longer open, error msg appears and... */
- { /* ...the app is muted */
- NormalCursor(currenttlFrame);
- return;
- }
- SenderOpenDocument(instrument->sender,
- instrument->currentNote->ms->documentName);
- result = SenderSetSelection(instrument->sender,
- instrument->currentNote->ms->selection);
- instrument->playNote = 1; /* Set flag so PerformSelection should be done for this note */
- if (currenttlFrame->syncHints == GeneratingSyncHints) /* Should synchronization hints be calculated? */
- { /* Yes, collect sync hints */
- gettimeofday(&after, (struct timezone*)NULL); /* Get time of day after OpenDoc & SetSelection complete */
- elapsedTime = (after.tv_sec - before.tv_sec) * 1000; /* Calculate time taken to execute the OpenDoc and... */
- elapsedTime += ((after.tv_usec - before.tv_usec) / 1000); /* ...SetSelection messages */
- instrument->currentNote->ms->setupTime = elapsedTime; /* Save this setup time as a hint for synchronization */
- }
- if (currenttlFrame->syncHints != SyncHintsAvailable) /* If messaging is synchronous, then wait a certain... */
- while (result != 0 && count < PingTimes) /* ...amount of time for SetSelection message to complete */
- {
- result = SenderPing(instrument->sender);
- count ++;
- }
- NormalCursor(currenttlFrame);
- return;
- } /* end function PrepareNoteForPerformance */
-
-
-
- void ResumeOrPerformSelections() /* Sends PerformSelection or ResumeSelection messages,... */
- { /* ...depending on the state of the current document... */
- int i; /* ...(whether pause mode or normal play, for example) */
- int startTime;
- Instrument* instrument;
-
- instrument = (Instrument *) FindInstrument(startApp, currenttlFrame);
- for (i=0; i < numApps; i++, instrument = instrument->next) /* Go through each instrument to see which has a note... */
- { /* ...to be played currently */
- if (instrument->currentNote == (Note*)NULL) /* If there is no note to consider for this instrument,... */
- continue; /* ...go on to the next instrument */
- startTime = instrument->currentNote->start + /* Determine starting time, taking into account... */
- (instrument->currentNote->ms->selection->offset / 100); /* ...partial selections if necessary */
- if ((instrument->playNote != 0) && /* Is it time to do the actual performance right now? */
- (startTime == virtualClock))
- {
- if ((xv_get(instrument->editInfo->MuteChoice, /* If application is muted or not running, skip to... */
- PANEL_VALUE) != 0) || /* ...the next available application */
- (CheckAppOpen(currenttlFrame, instrument, 0) != OK))
- continue;
- if ((currenttlFrame->status == ResumeMode || /* Should a ResumeSelection be sent? If the current... */
- currenttlFrame->status == ResumeSelectedMode) /* ...document is in one of the Resume modes and this... */
- && instrument->partialNote == 1) /* ...instrument was marked for partial note playback,... */
- { /* ...then a ResumeSelection message should be sent. */
- if (currenttlFrame->syncHints == SyncHintsAvailable) /* Pause turned off asynchronous communications; restore... */
- SenderSynchronousMessaging(instrument->sender, Off); /* ...if synchronization information is present. */
- SenderResumeSelection(instrument->sender);
- instrument->partialNote = 0;
- instrument->playNote = 0;
- }
- else
- {
- SenderPerformSelection(instrument->sender); /* If this statement is reached, a PerformSelection msg... */
- instrument->playNote = 0; /* ...should be sent. */
- }
- } /* end if ((instrument->playNote...)) */
- } /* end for */
- if (currenttlFrame->status == ResumeMode) /* Indicate that the document is now in one of the normal... */
- currenttlFrame->status = PlayMode; /* ...Play modes, since any "ResumeSelection" messages... */
- else if (currenttlFrame->status == ResumeSelectedMode) /* ...that may have been sent have been taken care of. */
- currenttlFrame->status = PlaySelectedMode;
- return;
- } /* end function ResumeOrPerformSelections */
-
-
-
- /*
- * FindNextNoteToPerform() -- Determines if the current instrument has
- * a note to prepare for performance.
- *
- * Essentially, this function compares the start time of the current
- * instrument's current note to that of the virtualClock. Since both are
- * in terms of the pixel position on the canvas, if they are equal, this
- * means the playback head is now at the start of that note and it should
- * be played. A note is also ready to be played if the playback head is
- * in the middle of the note. The function calls CalculateStartTime() to
- * take into account any synchronization hints that might be available
- * for this document. If there are, the startTime variable is adjusted
- * to take into account the time needed by the current note to prepare
- * for its performance.
- */
-
- Note* FindNextNoteToPerform(Instrument* instrument)
- {
- int done = 0;
- int startTime = 0;
-
- while (instrument->currentNote != NULL && !done) /* Traverse the whole list of notes for this instrument... */
- { /* ...until a note is found that needs to be played */
- startTime = CalculateStartTime(instrument); /* Get start time for this note */
- if (startTime < virtualClock && /* Was a note found that needs to be played? */
- instrument->currentNote->end <= virtualClock)
- instrument->currentNote = instrument->currentNote->next; /* No, go on to the next note */
- else /* Yes, break out of the loop and exit this function */
- done = 1;
- }
- return(instrument->currentNote);
- } /* end function FindNextNoteToPerform */
-
-
- void UpdateEndTime(Instrument* instrument) /* Determines whether global variable "endTime" needs to be... */
- { /* ...updated, and does the updating if necessary. */
- if ((instrument->currentNote->start +
- instrument->currentNote->ms->duration * 5) > endTime)
- { /* Check if the endTime needs to be updated */
- endTime = instrument->currentNote->start +
- instrument->currentNote->ms->duration * 5;
- }
- return;
- } /* end function UpdateEndTime */
-
-
-
- void StopPlayingSelection()
- {
- Instrument* instrument;
- int i;
-
- instrument = (Instrument *) FindInstrument(startApp, currenttlFrame);
- for (i=0; i < numApps; i++, instrument = instrument->next)
- {
- if (CheckAppOpen(currenttlFrame, instrument, 0) != OK) /* If app is no longer open, error message appears... */
- continue; /* ...and the app is muted */
- SenderSynchronousMessaging(instrument->sender, On); /* Assure that TimeLine blocks until HaltSelection completes */
- SenderHaltSelection(instrument->sender);
- PlayStop();
- }
- return;
- } /* end function StopPlayingSelection */
-
-
-
- void UpdateSyncHints(int finished)
- {
- if (virtualClock >= endTime && finished != 0) /* Was the whole document played? */
- { /* Yes: if TimeLine was generating sync hints, then... */
- if (currenttlFrame->syncHints == GeneratingSyncHints) /* ...flag this document as having sync hints */
- {
- currenttlFrame->syncHints = SyncHintsAvailable;
- currenttlFrame->change = 1; /* Document is modified due to addition of sync hints */
- UpdateHeader(currenttlFrame, 1);
- }
- }
- return;
- } /* end function UpdateSyncHints */
-
-
- /*
- * CalculateStartTime() -- A function to calculate the correct
- * starting performance time for a note on the TimeLine.
- * This function determines the correct starting time for the currentNote
- * of the instrument passed in as argument. It does so by taking into
- * account the desired starting time and taking into account any
- * synchronization hints that might be available for the currentNote. If
- * no syncHints are available, then the starting time for this note is
- * simply that time stored in currentNote->start. If syncHints are
- * available, the setupTime field of the currentNote is taken into
- * account, in effect setting the starting time to earlier than the
- * desired currentNote->start time. This is done to take into account
- * the times various media editors take to prepare their selections for
- * performance.
- * The return value is given in units of clock ticks (1/10th of a second).
- */
-
- int CalculateStartTime(Instrument* instrument)
- {
- int setupTime = 0;
-
- if (currenttlFrame->syncHints == SyncHintsAvailable) /* If sync hints available for this doc, take setupTime... */
- setupTime = instrument->currentNote->ms->setupTime / 100; /* ...into account, converting into clock ticks (1/10th sec) */
- return(instrument->currentNote->start - setupTime);
- } /* end function CalculateStartTime */
-